﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace ApiDoc
{
    /// <summary>
    /// Documentation for a assembly.
    /// </summary>
    public class AssemblyDocumentation : IMemberDocumentation
    {
        internal AssemblyDocumentation(Assembly member, ApiDocumentationManager manager)
        {
            Member = member;
            Manager = manager;
        }

        /// <summary>
        /// Gets the cref for the member.
        /// </summary>
        public string CRef
        {
            get
            {
                if (m_cref == null) {
                    // Generate the cref directly.
                    m_cref = Member.ManifestModule.Name;
                }

                return m_cref;
            }
        }

        private string m_cref;

        /// <summary>
        /// Returns the member.
        /// </summary>
        protected internal Assembly Member { get; protected set; }

        /// <summary>
        /// Returns the member.
        /// </summary>
        protected ApiDocumentationManager Manager { get; set; }

        /// <summary>
        /// IL Name of the type as returned by reflection.
        /// </summary>
        public string ILName
        {
            get { return Member.ManifestModule.Name; }
        }

        public string Name
        {
            get
            {
                return Member.ManifestModule.Name;
            }
        }

        public string CodeDefinition
        {
            get
            {
                return Member.ManifestModule.Name;
            }
        }

        /// <summary>
        /// Gets the assemblys that are within this assembly.
        /// </summary>
        public IEnumerable<NamespaceDocumentation> Namespaces
        {
            get
            {
                if (m_namespaces == null) {
                    // Find all types directly in this assembly.
                    m_namespaces = Manager.GetAssemblies()
                        .SelectMany(item => item.GetTypes())
                        .Where(item => item.Namespace != null)
                        .Where(item => item.Assembly == Member)
                        .Select(item => item.Namespace)
                        .Distinct()
                        .Select(item => Manager.GetNamespaceDocumentation(item))
                        .OrderBy(item => item.Name)
                        .ToList();
                }

                return m_namespaces;
            }
        }

        private IEnumerable<NamespaceDocumentation> m_namespaces;

        /// <summary>
        /// Gets the types contained within this assembly.
        /// </summary>
        public IEnumerable<TypeDocumentation> Types
        {
            get
            {
                if (m_types == null) {
                    // Find all types directly in this assembly.
                    m_types = Manager.GetAssemblies()
                        .SelectMany(item => item.GetTypes())
                        .Where(item => !item.IsSpecialName)
                        .Where(item => !item.IsDefined(typeof(CompilerGeneratedAttribute), false))
                        //.Where(item => (item.Attributes & TypeAttributes.NestedPrivate) == 0)
                        .Where(item => item.Assembly == Member)
                        .Select(item => Manager.GetTypeDocumentation(item))
                        .OrderBy(item => item.Name)
                        .ToList();
                }

                return m_types;
            }
        }

        /// <summary>
        /// Gets the interfaces contained within this assembly.
        /// </summary>
        public IEnumerable<TypeDocumentation> Interfaces
        {
            get
            {
                return Types.Where(item => item.Member.IsInterface);
            }
        }

        /// <summary>
        /// Gets the classes contained within this assembly.
        /// </summary>
        public IEnumerable<TypeDocumentation> Classes
        {
            get
            {
                return Types.Where(item => item.Member.IsClass);
            }
        }

        /// <summary>
        /// Gets the enums contained within this assembly.
        /// </summary>
        public IEnumerable<TypeDocumentation> Enums
        {
            get
            {
                return Types.Where(item => item.Member.IsEnum);
            }
        }

        private IEnumerable<TypeDocumentation> m_types;
    }
}
